class Appoint{
    /* new promise 需传入一个函数，每个实例须有自己的状态，预备一个解决结果 */
    constructor(handle=(res,rej)=> {}){
        /* 这部分代码仍是同步，只有then里面的代码要求是异步 */
        this['[[PromiseState]]'] = 'pending'
        this['[[PromiseResult]]'] = undefined;
        handle(this.#resolve.bind(this), this.#reject.bind(this))
        this.onResolveQueue = []
        this.onRejectQueue = []
    }
    /* 调用静态方法转变状态，改变结果 */
    #resolve(val) {
        this["[[PromiseState]]"] = 'fullfilled'
        this["[[PromiseResult]]"] = val
        const run = ()=> {

            for ( let res of this.onResolveQueue){
                res(val)
            }
            this.onResolveQueue = []
        }
        // new MutationObserver(run).observe(document.body, {attributes: true })
    }

    #reject(err){

        this["[[PromiseState]]"] = 'rejected'
        this["[[PromiseResult]]"] = err
        const run = ()=> {

            for(let rej of this.onRejectQueue){
                rej( err)
            }
            this.onRejectQueue =[]
        }
        // new MutationObserver(run).observe(document.body, {attributes: true })

    }
   /* then方法应该在状态变化之后立即执行  */
    then(resolve, rejecte){
        this.onRejectQueue.push(rejecte);
        this.onResolveQueue.push(resolve) ;
        /*  传递返回值，所以先拿到返回值，然后把它作为新期约的结果进行解决， 并且将新期约的创建作为一个当前then的回调函数 ，这样就能在当前then回调执行完之后，立即构建这个期约 */
        return new Appoint((res,rej)=> {
            let resovleFn = function(val){
                   let  result = resolve && resolve(val)
                if( result instanceof Appoint){
                    result.then(resolve)
                }else {
                    res(result)
                }
            }
            this.onResolveQueue.push( resovleFn)

            let  rejecteFn = function(val){
                    rejecte && rejecte(val)
                    rej(val)
            }
            this.onRejectQueue.push(rejecteFn)
        })
    }

    finall(val){
        /* 就是不论成功和失败都会调用 */
    }

    static race() {
        /* 思路就是给全部的期约都注册一个res回调 , 一旦有回调执行就改变状态，*/
    }
    /* 两个静态方法很简单， 主逻辑实现了，就是返回一个已经解决的期约 */
    static resolve(val){
        return new Appoint(((res, rej)=> {res(val)}))
    }
    static reject(err){
        return  new Appoint((res, rej)=> {rej(err)})
    }
}

let p = new Appoint((res, rej)=> {
    setTimeout(()=> {

        if( 1 > 3){
            rej(1)
        }else {
            res(3)
        }
    })
})
let p1 = Appoint.reject(0) , p2 = Appoint.resolve(1)
// console.log(p, p1,p2)

p.then((e)=> {
    console.log('%c'+e, 'color:red')
})



export  class Mpromise {
    constructor(handler){
        if( typeof handler !== 'function'){
           throw(`${handler} is not a function`)
        }
        this['[[state]]'] = 'pending'
        this['[[result]]'] = undefined ;
        this.rejectQue = []
        this.resolveQue = []
        handler(this.#resolve.bind(this),  this.#reject.bind(this))
    }

    #resolve(val){
        this['[[state]]'] = 'fullfilled'
        this['[[result]]'] = val ;
        queueMicrotask(()=> {

            while (this.resolveQue.length) {
                this.resolveQue.shift()(val)
            }
        })

    }
    /* 状态一改变立即执行全部 */
    #reject(val){
        this["[[state]]"] = 'rejected'
        this['[[result]]'] = val ;
        queueMicrotask(()=> {

            while (this.rejectQue.length) {
                this.rejectQue.shift()(val)
            }
        })
    }
    /* then只负责收集  这里还需要解决一个问题 then 的返回值 应当是一个promise，其结果是回调函数的返回值，状态和源promise一致。
        但是要拿到返回值 如何拿到返回值， 就是调用hook(val)的结果，所以又必须去拿到期约的结果
        then 的返回值期约的结果与其回调函数的返回值一致，因此不能直接返回this
    */
    then(onResolved, onRejected){
        if( onResolved){

            if( typeof onResolved !== 'function'){
                throw(`${onResolved} is not a function`)
            }
            this.resolveQue.push(onResolved)
        }
        if( onRejected){

            
            if( typeof onRejected !== 'function'){
                throw(`${onRejected} is not a function`)
            }
             this.rejectQue.push(onRejected)
        }
          return   new Promise((res, rej)=> {
            let resFn = (val)=> {
                let result = onResolved(val) ;
                /* 如果返回值是一个期约，那么就要等这个期约解决之后拿到它的结果 这就是地狱回调改链式调用 */
                if ( result instanceof Mpromise){
                    result.then(resFn) ;
                }else{

                    res(result)
                }
            } 
            this.resolveQue.push(resFn) ;

          })

    }
    catch(onRejected){
        return  this.then(null,onRejected)
        if(  typeof onRejected !== 'function'){
            throw(`${onRejected} is not a function`)
         }
          this.rejectQue.push(onResolved)

    }

    finally(fn){
        /* 效果和then一毛一样 区别是它不需要接收值 不传递返回值，只返回和源期约相同状态和结果的期约 */
        /* 原生实现还是返回了一个新的期约 */
        function handler(cb){
            return function(val){
                fn()
                cb(val)
            }
        }
        return new Mpromise((res,rej)=> {
             this.then(handler(res), handler(rej))

         })
    }
    /* 果然 定义多个静态属性会只认第一个 */
    static reject(val){
        return new Mpromise((res)=> { res(val)})
    }
    static resolve(val) {
        return  new Mpromise(((res, rej)=> {rej(val)}))
    }

}
Mpromise.resolve =(val)=>  {
    return  new Mpromise(((res, rej)=> {rej(val)}))
} 
Mpromise.race = function(ps=[]){
/* 这就需要一个柯理化了 同样的逻辑 不同的回调 */
    return  new Mpromise((res, rej) => {

        let first = false ;
        const handler = (cb)=>()=> {
            if(!first){
                first =true;
                /* 不论成败都落定 */
                cb(p)
            }
        }
        for( let p of ps ){
            if(!(p instanceof Mpromise)){ throw(`${p} is not a Mpromise`)}
            p.then(handler(res), handler(rej))
        }
    })
}
Mpromise.all = function(ps=[]){
    /* 其实这个和race有点像 只不过它抛出第一个reject  */
    let total = ps.length ;
    const  results = []

    return new Mpromise((res, rej)=> {

        const reshandler = (val)=> {
            results.push(val);
            if (results.length === total){
                /* 成功的回调是全部的结果 */
                res(results)
            }
        }
        const rejhandler = (val)=> {
            /* 失败的回调就是第一个失败的原因 */
            rej(val)
        }
        for ( let p of ps){
            p.then(reshandler, rejhandler)
        }
    })
}
Mpromise.allSettled = function(ps=[]){
    /* 这个就是全部落定  和race相对啊 */
    let total = ps.length ;
    const  results = []

    return new Mpromise((res, rej)=> {
        const handler =(cb)=> (val)=> {
            results.push(val);
            if (results.length === total){
                /* 成功的回调是全部的结果 */
                cb(results)
            }
        }

        for ( let p of ps){
            p.then(handler(res), handler(rej))
        }
    })
}



/* 第四阶段草案 2022 03 12 */
Mpromise.any = function(){
    Mpromise.all = function(ps=[]){
        /* 其实这个和race有点像 只不过它会等一个resolve  */
        let total = ps.length ;
        const  errs = []
    
        return new Mpromise((res, rej)=> {
    
            const reshandler = (val)=> {
                results.push(val);
                if (results.length === total){
                    /* 成功的回调是某个成功的结果 */
                    res(val)
                }
            }
            const rejhandler = (val)=> {
                /* 失败的回调就是第一个失败的原因 */
                errs.push(val)
                if(errs.length === total){

                    rej(errs)
                }
            }
            for ( let p of ps){
                p.then(reshandler, rejhandler)
            }
        })
    }
}




Promise.resolve().then().finally(()=>{})
console.log(

    Promise.race([ Promise.reject(12).catch(console.warn)])
) 

/* 
就是写个简单的异步 那就写个回调
promise 解决的问题  就是回调嵌套，都依赖于同一个异步，不用promise就可以解决这个问题，就是发布订阅。 */